#ifndef __WIN_VISUALIZE_HPP__
#define __WIN_VISUALIZE_HPP__
///////////////////////////////////
#include <windows.h>
#include <windowsx.h>
#include <boost/locale.hpp>
#include <unistd.h>

#include "../base.hpp"
#include "../Algorithm/gameSolver.hpp"
#include "../mapGenerator/generator.hpp"

// 绘制参数
int MARGIN = 30;
string tipText = "WASD: move ; \
Click: Navigate to the place, click with right button to push the box.";

// 主类
string path = "";

bool havebeensolved = false;
string pathText;

MainProcess mainp;
Navigator navigator;
GameSolver solver;
MapGenerator mapGen;

/// @brief 在窗口W绘制画面
void draw(HWND hWnd)
{
    // 获取窗口尺寸
    // 计算出每个方块的大小 = min((Width-margin*2)/w,(Heigh-margin*2)/h)
    HDC hdc = GetDC(hWnd);
    RECT clientRect;
    GetClientRect(hWnd, &clientRect);
    int width = clientRect.right - clientRect.left;
    int height = clientRect.bottom - clientRect.top;

    int h = mainp.state.map.size();
    int w = mainp.state.map[0].size();
    std::string s = mainp.toString();

    int blockSize = std::min((width - MARGIN * 2) / w, (height - MARGIN * 2) / h);

    // clear screen
    HBRUSH hbr = CreateSolidBrush(RGB(255, 255, 255));
    RECT rect = (RECT){0, MARGIN, width, height};
    FillRect(hdc, &rect, hbr);
    rect = (RECT){MARGIN * 2, MARGIN, width, MARGIN}; // 这里时为了防止按钮被覆盖
    FillRect(hdc, &rect, hbr);
    DeleteObject((HGDIOBJ)hbr);

    // 打字
    HFONT hFont = CreateFont(20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("Consolas"));
    SelectObject(hdc, hFont);
    SetBkMode(hdc, TRANSPARENT);
    SetTextColor(hdc, RGB(0, 0, 0));
    TextOutA(hdc, MARGIN * 6 + 5, 5, tipText.c_str(), tipText.size());

    // 遍历 s，根据对应的字符在窗口W绘制
    for (int y = 0; y < h; ++y)
    {
        for (int x = 0; x < w; ++x)
        {
            int charIndex = y * (w + 1) + x;
            rect = (RECT){MARGIN + x * blockSize+1, MARGIN + y * blockSize+1,
                          MARGIN + (x + 1) * blockSize-1, MARGIN + (y + 1) * blockSize-1};
            switch (s[charIndex])
            {
            case WALL:
                hbr = CreateSolidBrush(RGB(0, 0, 0));
                FillRect(hdc, &rect, hbr);
                DeleteObject((HGDIOBJ)hbr);
                break;
            case BOX:
                hbr = CreateSolidBrush(RGB(120, 30, 20));
                FillRect(hdc, &rect, hbr);
                DeleteObject((HGDIOBJ)hbr);
                break;
            case MAN:
                hbr = CreateSolidBrush(RGB(0, 255, 255));
                SelectObject(hdc, hbr);
                Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom);
                DeleteObject((HGDIOBJ)hbr);
                break;
            case TARGET:
                hbr = CreateSolidBrush(RGB(255, 200, 200));
                SelectObject(hdc, hbr);
                rect = (RECT){MARGIN + x * blockSize + blockSize / 4, MARGIN + y * blockSize + blockSize / 4,
                              MARGIN + (x + 1) * blockSize - blockSize / 4, MARGIN + (y + 1) * blockSize - +blockSize / 4};
                Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom);
                DeleteObject((HGDIOBJ)hbr);
                break;
            case BOX_T:
                hbr = CreateSolidBrush(RGB(150, 50, 30));
                FillRect(hdc, &rect, hbr);
                DeleteObject((HGDIOBJ)hbr);
                break;
            case MAN_T:
                hbr = CreateSolidBrush(RGB(100, 255, 255));
                SelectObject(hdc, hbr);
                Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom);
                DeleteObject((HGDIOBJ)hbr);
                break;
            }
        }
    }
    ReleaseDC(hWnd, hdc);
}

void AutoSolve(HWND hWnd)
{
    if (!havebeensolved)
    {
        pathText = solver.solve(mainp.state);
        havebeensolved = true;
    }
    for (int i = 0; i < pathText.size(); i++)
    {
        mainp.MoveToward(pathText[i]);
        draw(hWnd);
        usleep(100000);
    }
}

Point2D mouseClick(HWND hWnd, int x, int y, bool ifpushbox)
{
    RECT clientRect;
    GetClientRect(hWnd, &clientRect);
    // 获得点击的格子的坐标
    int blockSize = std::min((clientRect.right - clientRect.left - MARGIN * 2) / mainp.state.map[0].size(),
                             (clientRect.bottom - clientRect.top - MARGIN * 2) / mainp.state.map.size());
    int gridX = (x - MARGIN) / blockSize;
    int gridY = (y - MARGIN) / blockSize;
    // 如果在范围内就开启导航
    if (gridX >= 0 && gridX < mainp.state.map[0].size() &&
        gridY >= 0 && gridY < mainp.state.map.size())
        if (!mainp.state.map[gridY][gridX])
        {
            navigator.init(mainp.state.map, !ifpushbox ? mainp.state.box : vector<Point2D>());
            pathText = navigator.path2cmd(navigator.navigate(mainp.state.man, {gridX, gridY}));
            for (int i = 0; i < pathText.size(); i++)
            {
                mainp.MoveToward(pathText[i]);
                draw(hWnd);
                usleep(200000);
            }
        }
    return {-1, -1};
    return {gridX, gridY};
}

int keyInput(int key)
{
    switch (key)
    {
    case 'w':
    case 'W':
        return mainp.MoveToward('W');
    case 'a':
    case 'A':
        return mainp.MoveToward('A');
    case 's':
    case 'S':
        return mainp.MoveToward('S');
    case 'd':
    case 'D':
        return mainp.MoveToward('D');
    }
    return -1;
}

/// @brief 解析命令行参数
/// @param lpCmdLine
void ParseCommandLine(LPSTR lpCmdLine)
{
    // 分割命令行参数
    string tmp, s = lpCmdLine;
    // cout << s << endl;
    for (int i = 0; i < s.size(); i++)
    {
        if (s[i] == ' ')
        {
            break;
            tmp = "";
        }
        tmp += s[i];
    }
    if (tmp.size())
        path = tmp;
}

// 几个转码函数
string tcharArrayToString(const TCHAR *tcharArray)
{
    return string(reinterpret_cast<const char *>(tcharArray));
}
LPCWSTR stringToLPCWSTR(const std::string &str)
{
    std::wstring wideStr = reinterpret_cast<const wchar_t *>(str.c_str());
    return wideStr.c_str();
}

/////////////////////////////////////////////
#endif